package com.shop.zzh.config;

import com.shop.zzh.component.jwt.RestAuthenticationEntryPoint;
import com.shop.zzh.component.jwt.RestfulAccessDeniedHandler;
import com.shop.zzh.entity.User;
import com.shop.zzh.dto.AdminUserDetails;
import com.shop.zzh.filter.JwtAuthenticationTokenFilter;
import com.shop.zzh.mbg.model.UserPermission;
import com.shop.zzh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.List;

/**
 * @program: zzh
 * @description: Security的配置类
 * @author: zhuzh
 * @create: 2019-12-16 22:08
 **/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private UserService userService;

	@Override
	protected void configure(HttpSecurity httpSecurity) throws Exception {
		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
				.authorizeRequests();
		//不需要保护的资源路径允许访问
		for (String url : ignoreUrlsConfig().getUrls()) {
			System.out.println(url);
			registry.antMatchers(url).permitAll();
		}
		//允许跨域请求的OPTIONS请求
		registry.antMatchers(HttpMethod.OPTIONS)
				.permitAll();
		// 任何请求需要身份认证
		registry.and()
				.authorizeRequests()
				.anyRequest()
				.authenticated()
				// 关闭跨站请求防护及不使用session
				.and()
				.csrf()
				.disable()
				.sessionManagement()
				.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
				// 自定义权限拒绝处理类
				.and()
				.exceptionHandling()
				.accessDeniedHandler(restfulAccessDeniedHandler())
				.authenticationEntryPoint(restAuthenticationEntryPoint())
				// 自定义权限拦截器JWT过滤器
				.and()
				.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);

//				.csrf().disable()// 由于使用的是JWT，我们这里不需要csrf
//				//只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面maximumSessions(1).expiredUrl("/zzh/zc/login.do")
//				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 基于token，所以不需要session
//				.authorizeRequests()
//				.antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
//						"/resources/**",
//						"/layui/**",
//						"/",
//						"/*.html",
//						"/favicon.ico",
//						"/**/*.html",
//						"/**/*.css",
//						"/**/*.js",
//						"/**/*.png",
//						"/**/*.jpg",
//						"/swagger-resources/**",
//						"/v2/api-docs/**"
//				).permitAll()
//				.antMatchers("/zzh/zc/login.do", "/zzh/zc/register.do","/zzh/zc/welComeLogin.do","/zzh/zc/checkUser.do","/common/json/header.json")// 对登录注册要允许匿名访问
//				.permitAll()
//				//系统相关、非业务接口只能是管理员以上有权限，例如
////				.antMatchers("").hasAnyAuthority("ROLE_ADMIN","ROLE_SA")
//				.antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
//				.permitAll()
//				.anyRequest()// 除上面外的所有请求全部需要鉴权认证
//				.authenticated()
////				.and()
////				.formLogin()
////				.loginProcessingUrl("/zzh/zc/login.do")
////				.loginPage("login/loginIndex")
//		;
//		// 禁用缓存
//		httpSecurity.headers().cacheControl();
//		// 添加JWT filter
//		httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//		//添加自定义未授权和未登录结果返回
//		httpSecurity.exceptionHandling()
//				.accessDeniedHandler(restfulAccessDeniedHandler)
//				.authenticationEntryPoint(restAuthenticationEntryPoint);
////		httpSecurity.exceptionHandling().accessDeniedPage("/");
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService()) // 设置UserDetailsService
				// 使用BCrypt进行密码的hash
				.passwordEncoder(passwordEncoder());
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
		return new JwtAuthenticationTokenFilter();
	}

	@Bean
	public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
		return new RestfulAccessDeniedHandler();
	}

	@Bean
	public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
		return new RestAuthenticationEntryPoint();
	}

	@Bean
	public IgnoreUrlsConfig ignoreUrlsConfig() {
		return new IgnoreUrlsConfig();
	}

	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

//	@Bean
//	public JwtTokenUtil jwtTokenUtil() {
//		return new JwtTokenUtil();
//	}

	@Bean
	public UserDetailsService userDetailsService() {
		//获取登录用户信息
		return username -> {
			User user = userService.selectOnByUserName(username);
			if (user != null) {
				List<UserPermission> permissionList = userService.getPermissionList(user.getId());
				return new AdminUserDetails(user,permissionList);
			}
			throw new UsernameNotFoundException("用户名或密码错误");
		};
	}

}
